﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SlimDX;

namespace SCS.GFX
{
    class Camera
    {
        static Vector3 InitialPos= new Vector3(0.0f,0.0f,-10.0f);
        static Vector3 InitialTarget = new Vector3(0.0f, 0.0f, 0.0f);


        Vector3 FLocation = InitialPos;
        Vector3 FTarget = InitialTarget;
        float ZPos;
        float XPos;
        float Heading;

        float Rad90 = 1.570796327f;
        float speed = 0.2f;

        public void Reset()
        {
            FLocation = InitialPos;
            FTarget = InitialTarget;
            ZPos = 0;
            XPos = 0;
            Heading = 0;

        }


        public void RotateLeft(float speed)
        {
            Heading = Heading + speed;
            RotateAroundPoint(FTarget, -speed, new Vector3(0.0f, 1.0f, 0.0f));
            UpdateView();
        }

        public void RotateRight(float speed)
        {
            Heading = Heading - speed;
            RotateAroundPoint(FTarget, speed, new Vector3(0.0f, 1.0f, 0.0f));
            UpdateView();

        }

        public void RotateAroundPoint(Vector3 Target, float angle, Vector3 Axis)
        {
            Vector3 CameraPosition;
            Vector3 Pos;
            Vector3 Center;
            Vector3 NewPosition;
            float cosTheta;
            float sinTheta;

            CameraPosition = FLocation;
            Center = Target;
            Pos = Vector3.Subtract(CameraPosition, Center);

            cosTheta = (float)Math.Cos(angle);
            sinTheta = (float)Math.Sin(angle);


            // Find the new x position for the new rotated point
            NewPosition.X = (cosTheta + (1 - cosTheta) * Axis.X * Axis.X)		* Pos.X;
            NewPosition.X = NewPosition.X + ((1 - cosTheta) * Axis.X * Axis.Y - Axis.Z * sinTheta) * Pos.Y;
            NewPosition.X = NewPosition.X + ((1 - cosTheta) * Axis.X * Axis.Z + Axis.Y * sinTheta) * Pos.Z;

            // Find the new y position for the new rotated point
            NewPosition.Y = ((1 - cosTheta) * Axis.X * Axis.Y + Axis.Z * sinTheta) * Pos.X;
            NewPosition.Y = NewPosition.Y + (cosTheta + (1 - cosTheta) * Axis.Y * Axis.Y) * Pos.Y;
            NewPosition.Y = NewPosition.Y + ((1 - cosTheta) * Axis.Y * Axis.Z - Axis.X * sinTheta) * Pos.Z;

            // Find the new z position for the new rotated point
            NewPosition.Z = ((1 - cosTheta) * Axis.X * Axis.Z - Axis.Y * sinTheta) * Pos.X;
            NewPosition.Z = NewPosition.Z + ((1 - cosTheta) * Axis.Y * Axis.Z + Axis.X * sinTheta) * Pos.Y;
            NewPosition.Z = NewPosition.Z + (cosTheta + (1 - cosTheta) * Axis.Z * Axis.Z) * Pos.Z;


            CameraPosition = Vector3.Add(NewPosition,Center);
            FLocation = CameraPosition;
            

        }



        public void MoveBackward(float dist)
        {
            double S;
            double C;

            S = Math.Sin(Heading);
            C = Math.Cos(Heading);

            S = S * dist;
            C = C * dist;

            FLocation.X = FLocation.X + (float)S;
            FLocation.Z = FLocation.Z - (float)C;

            FTarget.X = FTarget.X + (float)S;
            FTarget.Z = FTarget.Z - (float)C;
            UpdateView();
        }

        public void MoveForward(float dist)
        {
            double S;
            double C;

            S = Math.Sin(Heading);
            C = Math.Cos(Heading);

            S = S * dist;
            C = C * dist;

            FLocation.X = FLocation.X - (float)S;
            FLocation.Z = FLocation.Z + (float)C;

            FTarget.X = FTarget.X - (float)S;
            FTarget.Z = FTarget.Z + (float)C;
            UpdateView();
        }

        public void MoveLeft(float dist)
        {
            double S;
            double C;

            S = Math.Sin(Heading-Rad90);
            C = Math.Cos(Heading-Rad90);

            S = S * dist;
            C = C * dist;

            FLocation.X = FLocation.X + (float)S;
            FLocation.Z = FLocation.Z - (float)C;

            FTarget.X = FTarget.X +(float)S;
            FTarget.Z = FTarget.Z -(float)C;
            UpdateView();
        }

        public void MoveRight(float dist)
        {
            double S;
            double C;

            S = Math.Sin(Heading+Rad90);
            C = Math.Cos(Heading+Rad90);

            S = S * dist;
            C = C * dist;

            FLocation.X = FLocation.X + (float)S;
            FLocation.Z = FLocation.Z - (float)C;

            FTarget.X = FTarget.X + (float)S;
            FTarget.Z = FTarget.Z - (float)C;

            UpdateView();
        
        }


        public void MoveUp(float dist)
        {
            FLocation.Y += dist * speed;
            FTarget.Y += dist * speed;
            UpdateView();
        }
        public void MoveDown(float dist)
        {
            FLocation.Y -= dist * speed;
            FTarget.Y -= dist * speed;
            UpdateView();
        }

        public void UpdateView()
        {
            Renderer.View = Matrix.LookAtLH(FLocation,FTarget, Vector3.UnitY);
        }
    }
}
